/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

// 三种状态用常量表示
const PENDING = 'pending'  // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected'  // 失败

// 检查x返回值
function resolvePromise(p2, x, resolve, reject) {
    // 识别promise自返回
    if (p2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof Mypromise) {
        // x为primose对象 判断他的状态
        x.then((value) => {
            resolve(value)
        }, (reason) => {
            reject(reason)
        })

    }
    resolve(x)
}

class Mypromise {
    constructor(execoutor) {
        // 执行器内可能会报错
        try {
            execoutor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }

    }
    // 初始状态,值
    status = PENDING
    value = undefined   // 成功的值
    reason = undefined   // 失败原因
    successCallback = []  // 成功回调
    failCallback = []   //  失败回调
    resolve = (value) => {
        // 状态一旦确定就不能改变
        if (this.status !== PENDING) return
        this.status = FULFILLED
        this.value = value
        while (this.successCallback.length) {
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        // 状态一旦确定就不能改变
        if (this.status !== PENDING) return
        this.status = REJECTED
        this.reason = reason
        while (this.failCallback.length) {
            this.failCallback.shift()()
        }
    }
    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        // then为可链式调用
        let p2 = new Mypromise((resolve, reject) => {
            // 下一个promise的值为上一个的返回值
            // 判断x的值为普通值，还是promise对象
            // 如果是普通值，直接调用resolve
            // 如果是promise对象，判断其状态，成功调用resolve，失败调用reject
            if (this.status === FULFILLED) {
                // 状态为成功
                setTimeout(() => {
                    // 回调函数异常处理
                    try {
                        let x = successCallback(this.value)
                        resolvePromise(p2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }

                }, 0)


            } else if (this.status === REJECTED) {
                // 状态为失败
                setTimeout(() => {
                    // 回调函数异常处理
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(p2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }

                }, 0)

            } else {
                // 状态为等待

                this.successCallback.push(() => {
                    setTimeout(() => {
                        // 回调函数异常处理
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(p2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }

                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        // 回调函数异常处理
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(p2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }

                    }, 0)
                })



            }
        })
        return p2

    }

    // catch方法就是then方法成功回调为undefined
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }

    // finally方法不管是成功还是失败状态都会执行


    finally(callback) {
        return this.then((value) => {

            return Mypromise.resolve(callback()).then(() => {
                return value
            })
        }, (reason) => {

            return Mypromise.resolve(callback()).then(() => {
                throw reason
            })
        })
    }

    // all方法解决异步并发问题
    static all(array) {
        let res = []
        let num = 0
        return new Mypromise((resolve, reject) => {
            // 没有失败的状态时返回的结果数组
            function addData(index, data) {
                res[index] = data
                num++
                // 确定所有项都已经执行完成才resolve
                if (num === array.length) {
                    resolve(res)
                }
            }
            for (let index = 0; index < array.length; index++) {
                let curry = array[index]
                // 是普通值直接传入结果数组，是promise对象判断状态
                // 成功状态按调用顺序把结果传入结果数组
                // all方法所有的promise状态为成功才resolve，有一个失败则reject
                if (curry instanceof Mypromise) {
                    curry.then((value) => {
                        addData(index, value)
                    }, (reason) => {
                        reject(reason)
                    })

                } else {
                    addData(index, curry)
                }

            }
        })

    }

    // resolve x为promise对象直接返回，x为普通值，转化为promise对象
    static resolve(x) {
        if (x instanceof Mypromise) {
            return x
        }
        return new Mypromise((resolve) => {
            resolve(x)
        })
    }
}